/**
 * Copyright (C) 2013 Christos Koufogiannakis
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.easychart.chart;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;

public class PieChart extends ChartBaseClass{

	private class MyPoint{
		float x = -1;
		float y = -1;		
	}
	
	private List<Double> pieValues = new ArrayList<Double>();
	private double sum = 0;
	private int numberOfPieSlices;
	private MyPoint center = new MyPoint();
	private RectF oval = new RectF();
	private static Random rand = new Random();
	
	/** 
	 * Constructor for PieChart
	 * 
	 * @param context
	 * @param attrs
	 */
	public PieChart(Context context, AttributeSet attrs) {			
		super(context, attrs);	
		initialize();
	}
	
	/** 
	 * Constructor for PieChart
	 * 
	 * @param context
	 */
	public PieChart(Context context) {
		super(context);
		initialize();
	}
	/**
	 * Initializes PieChart specific parameters
	 */
	private void initialize(){	
		parameters.SHOW_LEGEND.setValue(true);
	}
	
	/**
	 * Set the list of values for the pie and the list of corresponding labels
	 *  
	 * @param values is the list of values to be plotted
	 * @param labels is the list of labels corresponding to the values. 
	 * The size of barLabels must be same as the size of values.
	 * 
	 * @throws IllegalArgumentException if values is null or
	 * the two lists have different sizes
	 */
	public void setValuesAndLabels(List<Double> values, List<String> labels) 
			throws IllegalArgumentException {
		checkNullity(values);
		this.pieValues = values;
		
		if (labels == null || values.size() != labels.size()){
			throw new IllegalArgumentException("The two list cannot be of different sizes");
		}
		else{
			super.setXLabels(labels);
		}	
	}
		
	protected void onDraw(Canvas canvas) {
		// first call initBackground of the base class
		super.initBackground(canvas);
		
		sum = 0;
		for (int i = 0; i<pieValues.size(); i++) {
			sum += pieValues.get(i);
		}
		
		numberOfPieSlices = Math.min(pieValues.size(), xLabels.size());
		int numOfColors = colorsArray.size();
		// add random colors if not enough colors in colorsArray
		for (int i = numOfColors; i < numberOfPieSlices; i++) {	
			int newColor = rand.nextInt(0xffffff + 0xa) + 0xff000000;
			colorsArray.add(newColor);
		}
		
		if (parameters.SHOW_LEGEND.getValue()) {		
			legendLabels = new String[numberOfPieSlices];
			for (int i = 0; i < numberOfPieSlices; i++) {
				legendLabels[i] = xLabels.get(i) + ": " + labelValueToString(pieValues.get(i), true) +
						" (" +  labelValueToString(100*pieValues.get(i)/sum, true) +  "%)";
			}
			super.drawLegend(canvas);
		}
		else {
			legendTopY = viewHeight;
		}
			
		mPaint.setTextSize(vertexLabelTextSize);
		
		if (numberOfPieSlices < 1 || !parameters.SHOW_PIE_LABELS.getValue()) {
			mPaint.getTextBounds("", 0, 0, bounds);	
		}
		else {
			int max_index = 0;
			for (int i = 0; i < numberOfPieSlices; i++) {
				if (xLabels.get(i).length() > xLabels.get(max_index).length()) {
					max_index = i;
				}
			}
			mPaint.getTextBounds(xLabels.get(max_index), 0, xLabels.get(max_index).length(), bounds);	
		}
		
		float plotTitleBottomY = parameters.PLOT_TITLE_TOP_TO_BORDER.getValue() + plotTitleTextSize;
		float horizontalMargin = (parameters.BORDER_TO_PIE.getValue() > bounds.width() ?
				parameters.BORDER_TO_PIE.getValue(): bounds.width());
		float availableWidth = viewWidth - 2*horizontalMargin;
		float availableHeight = legendTopY - plotTitleBottomY 
				- parameters.BORDER_TO_PIE.getValue() - 2*vertexLabelTextSize;
		 
		// find the min for available width or height
		float diameter = (availableWidth > availableHeight ? availableHeight : availableWidth);
		float radius = diameter/2;
		
		plotLeftX = (viewWidth - diameter)/2;
		plotRightX = plotLeftX + diameter;
		plotTopY = plotTitleBottomY + parameters.BORDER_TO_PIE.getValue()/2 
				+ vertexLabelTextSize + (availableHeight - diameter)/2 ;
		plotBottomY = plotTopY + diameter;
		
		// draw the chart title
		super.drawPlotTitle(canvas);
		
		// set the bounds of the pie
		oval.set(plotLeftX, plotTopY, plotRightX, plotBottomY);			
		//center of pie
		center.x =  (plotLeftX + plotRightX)/2;
		center.y =  (plotTopY + plotBottomY)/2;
							
		mPaint.setStyle(Style.FILL);
		float startAangle = 0;
		for (int i = 0; i < numberOfPieSlices; i++){
			// draw one pie slice at a time
			mPaint.setColor(colorsArray.get(i));
			float sweepAngle = (float) (360f * pieValues.get(i)/sum);
			canvas.drawArc(oval, startAangle, sweepAngle, true, mPaint);
			
			// find center of arc point
			MyPoint arc_center  = nextPointOnArcClockwise(
					radius, 360 - (startAangle  + sweepAngle/2), center);	
			
			if (parameters.SHOW_PIE_LABELS.getValue()){
				float xOffset;
				float Yoffset;
				final float offset = 2f;
				
				if (arc_center.x < center.x){			
					mPaint.setTextAlign(Align.RIGHT);
					xOffset = -offset;
				}
				else{
					mPaint.setTextAlign(Align.LEFT);
					xOffset = offset;
				}
				
				if (arc_center.y < center.y)		
					Yoffset = -offset;
				else
					Yoffset = offset + vertexLabelTextSize;
				
				mPaint.setColor(parameters.VERTEX_LABELS_TEXT_COLOR.getValue());
				mPaint.setTextSize(vertexLabelTextSize);
				canvas.drawText(xLabels.get(i), arc_center.x + xOffset, arc_center.y + Yoffset, mPaint);
			}
	
			startAangle += sweepAngle;
		}
	}
	
	private MyPoint nextPointOnArcClockwise(float radius, float theta, MyPoint center){
		MyPoint retPoint = new MyPoint();
	
		double thetaRadians =  theta * Math.PI/180.0;	
		double deltaX = radius * Math.cos(thetaRadians);
		double deltaY = radius * Math.sin(thetaRadians);
		
		//shift by center coordinates
		retPoint.x = (float) (center.x + deltaX); 
		// - delta because the canvas coordinate system increases from top to bottom
		retPoint.y =  (float) (center.y - deltaY);	
						
		return retPoint;
	}
}